home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / access / transam / transsup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  18.6 KB  |  711 lines

  1. /* ----------------------------------------------------------------
  2.  *   FILE
  3.  *    transsup.c
  4.  *    
  5.  *   DESCRIPTION
  6.  *    postgres transaction access method support code
  7.  *
  8.  *   INTERFACE ROUTINES
  9.  *     AmiTransactionOverride
  10.  *    CreateTransRelation
  11.  *
  12.  *    TransBlockNumberGetXidStatus
  13.  *    TransBlockNumberSetXidStatus
  14.  *    TransBlockNumberGetCommitTime
  15.  *    TransBlockNumberSetCommitTime
  16.  *    TransGetLastRecordedTransaction
  17.  *
  18.  *   NOTES
  19.  *    This file contains support functions for the high
  20.  *    level access method interface routines found in transam.c
  21.  *
  22.  * ----------------------------------------------------------------
  23.  */
  24.  
  25. #include "tmp/postgres.h"
  26.  
  27.  RcsId("$Header: /private/postgres/src/access/transam/RCS/transsup.c,v 1.12 1992/07/13 03:15:48 hong Exp $");
  28.  
  29. #include "machine.h"        /* in port/ directory (needed for BLCKSZ) */
  30.  
  31. #include "storage/buf.h"
  32. #include "storage/bufmgr.h"
  33.  
  34. #include "utils/rel.h"
  35. #include "utils/log.h"
  36. #include "utils/nabstime.h"
  37. #include "tmp/bit.h"
  38.  
  39. #include "access/transam.h"
  40.  
  41. #include "storage/smgr.h"
  42.  
  43. /* ----------------------------------------------------------------
  44.  *              general support routines
  45.  * ----------------------------------------------------------------
  46.  */
  47.     
  48. /* --------------------------------
  49.  *    AmiTransactionOverride
  50.  *
  51.  *    This function is used to manipulate the bootstrap flag.
  52.  * --------------------------------
  53.  */
  54. void
  55. AmiTransactionOverride(flag)
  56.     bool flag;
  57. {
  58.     AMI_OVERRIDE = flag;
  59. }
  60.  
  61. /* --------------------
  62.  *    CreateTransRelation
  63.  *
  64.  *    This function does the work of creating the given specified
  65.  *    relation using a dummy schema.  DummyAttributeTupleForm is
  66.  *    actually a macro in lib/H/catalog/pg_attribute.h.
  67.  * --------------------
  68.  */
  69.  
  70. AttributeTupleFormData    DummyAtt1 = DummyAttributeTupleForm;
  71. AttributeTupleForm      DummyTupleDescriptor[ 1 ] = { &DummyAtt1 };
  72.  
  73. void
  74. CreateTransRelation(name)
  75.     Name name;            /* relation name */
  76. {
  77.     heap_create(name, 'n', 1, DEFAULT_SMGR, DummyTupleDescriptor);
  78. }
  79.  
  80. /* --------------------------------
  81.  *    TransComputeBlockNumber
  82.  * --------------------------------
  83.  */
  84. void
  85. TransComputeBlockNumber(relation, transactionId, blockNumberOutP)
  86.     Relation              relation;     /* relation to test */
  87.     TransactionId         transactionId;     /* transaction id to test */
  88.     BlockNumber            *blockNumberOutP;
  89. {
  90.     long    itemsPerBlock;
  91.     
  92.     /* ----------------
  93.      *  we calculate the block number of our transaction
  94.      *  by dividing the transaction id by the number of
  95.      *  transaction things per block.  
  96.      * ----------------
  97.      */
  98.     if (relation == LogRelation)
  99.     itemsPerBlock = TP_NumXidStatusPerBlock;
  100.     else if (relation == TimeRelation)
  101.     itemsPerBlock = TP_NumTimePerBlock;
  102.     else
  103.     elog(WARN, "TransComputeBlockNumber: unknown relation");
  104.     
  105.     /* ----------------
  106.      *    warning! if the transaction id's get too large
  107.      *  then a BlockNumber may not be large enough to hold the results
  108.      *  of our division.
  109.      *
  110.      *    XXX  this will all vanish soon when we implement an improved
  111.      *       transaction id schema -cim 3/23/90
  112.      *
  113.      *  This has vanished now that xid's are 4 bytes (no longer 5).
  114.      *  -mer 5/24/92
  115.      * ----------------
  116.      */
  117.     (*blockNumberOutP) = transactionId / itemsPerBlock;
  118. }
  119.  
  120.  
  121. /* ----------------------------------------------------------------
  122.  *             trans block support routines
  123.  * ----------------------------------------------------------------
  124.  */
  125.   
  126. /* --------------------------------
  127.  *    TransBlockGetLastTransactionIdStatus
  128.  *
  129.  *    This returns the status and transaction id of the last
  130.  *    transaction information recorded on the given TransBlock.
  131.  * --------------------------------
  132.  */
  133.  
  134. XidStatus
  135. TransBlockGetLastTransactionIdStatus(tblock, baseXid, returnXidP)
  136.     Pointer        tblock;
  137.     TransactionId    baseXid;
  138.     TransactionId    *returnXidP;  /* RETURN */
  139. {
  140.     Index         index;
  141.     Index         maxIndex;
  142.     bits8         bit1;
  143.     bits8      bit2;
  144.     BitIndex      offset;
  145.     TransactionId TTupXid;
  146.     XidStatus     xstatus;
  147.  
  148.     /* ----------------
  149.      *    sanity check
  150.      * ----------------
  151.      */
  152.     Assert((tblock != NULL));
  153.  
  154.     /* ----------------
  155.      *    search downward from the top of the block data, looking
  156.      *  for the first Non-in progress transaction status.  Since we
  157.      *  are scanning backward, this will be last recorded transaction
  158.      *  status on the block.
  159.      * ----------------
  160.      */
  161.     maxIndex = TP_NumXidStatusPerBlock;
  162.     for (index = maxIndex-1; index>=0; index--) {
  163.     offset =  BitIndexOf(index);
  164.     bit1 =    ((bits8) BitArrayBitIsSet((BitArray) tblock, offset++)) << 1;
  165.     bit2 =    (bits8)  BitArrayBitIsSet((BitArray) tblock, offset);
  166.     
  167.     xstatus =  (bit1 | bit2) ;
  168.  
  169.     /* ----------------
  170.      *  here we have the status of some transaction, so test
  171.      *  if the status is recorded as "in progress".  If so, then
  172.      *  we save the transaction id in the place specified by the caller.
  173.      * ----------------
  174.      */
  175.     if (xstatus != XID_INPROGRESS) {
  176.         if (returnXidP != NULL) {
  177.         TransactionIdStore(baseXid, returnXidP);
  178.         TransactionIdAdd(returnXidP, index);
  179.         }
  180.         break;
  181.     }
  182.     }
  183.  
  184.     /* ----------------
  185.      *    if we get here and index is 0 it means we couldn't find
  186.      *  a non-inprogress transaction on the block.  For now we just
  187.      *  return this info to the user.  They can check if the return
  188.      *  status is "in progress" to know this condition has arisen.
  189.      * ----------------
  190.      */
  191.     if (index == 0) {
  192.     if (returnXidP != NULL)
  193.         TransactionIdStore(baseXid, returnXidP);
  194.     }
  195.  
  196.     /* ----------------
  197.      *    return the status to the user
  198.      * ----------------
  199.      */
  200.     return xstatus;
  201. }
  202.  
  203. /* --------------------------------
  204.  *    TransBlockGetXidStatus
  205.  *
  206.  *    This returns the status of the desired transaction
  207.  * --------------------------------
  208.  */
  209.  
  210. XidStatus
  211. TransBlockGetXidStatus(tblock, transactionId)
  212.     Pointer        tblock;
  213.     TransactionId    transactionId;
  214. {
  215.     TransactionIdValueData    xidv;
  216.     TransactionIdValueData     itemsPerBlock;
  217.     TransactionIdValueData     result;
  218.     Index               index;
  219.     bits8               bit1;
  220.     bits8            bit2;
  221.     BitIndex            offset;
  222.  
  223.     /* ----------------
  224.      *    sanity check
  225.      * ----------------
  226.      */
  227.     if (tblock == NULL) {
  228.     return XID_INVALID;
  229.     }
  230.  
  231.     /* ----------------
  232.      *    calculate the index into the transaction data where
  233.      *  our transaction status is located
  234.      *
  235.      *  XXX this will be replaced soon when we move to the
  236.      *      new transaction id scheme -cim 3/23/90
  237.      *
  238.      *  The old system has now been replaced. -mer 5/24/92
  239.      * ----------------
  240.      */
  241.     index = transactionId % TP_NumXidStatusPerBlock;
  242.    
  243.     /* ----------------
  244.      *    get the data at the specified index
  245.      * ----------------
  246.      */
  247.     offset =    BitIndexOf(index);
  248.     bit1 =      ((bits8)   BitArrayBitIsSet((BitArray) tblock, offset++)) << 1;
  249.     bit2 =      (bits8)    BitArrayBitIsSet((BitArray) tblock, offset);
  250.     
  251.     /* ----------------
  252.      *    return the transaction status to the caller
  253.      * ----------------
  254.      */
  255.     return (XidStatus)
  256.     (bit1 | bit2);
  257. }
  258.  
  259. /* --------------------------------
  260.  *    TransBlockSetXidStatus
  261.  *
  262.  *    This sets the status of the desired transaction
  263.  * --------------------------------
  264.  */
  265.  
  266. void
  267. TransBlockSetXidStatus(tblock, transactionId, xstatus)
  268.     Pointer        tblock;
  269.     TransactionId    transactionId;
  270.     XidStatus         xstatus;
  271. {
  272.     TransactionIdValueData    xidv;
  273.     Index               index;
  274.     BitIndex            offset;
  275.     TransactionIdValueData     itemsPerBlock;
  276.     TransactionIdValueData     result;
  277.     
  278.     /* ----------------
  279.      *    sanity check
  280.      * ----------------
  281.      */
  282.     if (tblock == NULL)
  283.     return;
  284.     
  285.     /* ----------------
  286.      *    calculate the index into the transaction data where
  287.      *  we sould store our transaction status.
  288.      *
  289.      *  XXX this will be replaced soon when we move to the
  290.      *      new transaction id scheme -cim 3/23/90
  291.      *
  292.      *  The new scheme is here -mer 5/24/92
  293.      * ----------------
  294.      */
  295.     index = transactionId % TP_NumXidStatusPerBlock;
  296.     
  297.     offset =    BitIndexOf(index);
  298.     
  299.     /* ----------------
  300.      *    store the transaction value at the specified offset
  301.      * ----------------
  302.      */
  303.     switch(xstatus) {
  304.     case XID_COMMIT:             /* set 10 */
  305.     BitArraySetBit((BitArray) tblock, offset);
  306.     BitArrayClearBit((BitArray) tblock, offset + 1);
  307.     break;
  308.     case XID_ABORT:             /* set 01 */
  309.     BitArrayClearBit((BitArray) tblock, offset);
  310.     BitArraySetBit((BitArray) tblock, offset + 1);
  311.     break;
  312.     case XID_INPROGRESS:        /* set 00 */
  313.     BitArrayClearBit((BitArray) tblock, offset);
  314.     BitArrayClearBit((BitArray) tblock, offset + 1);
  315.     break;
  316.     default:
  317.     elog(NOTICE,
  318.          "TransBlockSetXidStatus: invalid status: %d (ignored)",
  319.          xstatus);
  320.     break;
  321.     }
  322. }
  323.  
  324. /* --------------------------------
  325.  *    TransBlockGetCommitTime
  326.  *
  327.  *    This returns the transaction commit time for the
  328.  *    specified transaction id in the trans block.
  329.  * --------------------------------
  330.  */
  331.  
  332. Time
  333. TransBlockGetCommitTime(tblock, transactionId)
  334.     Pointer        tblock;
  335.     TransactionId    transactionId;
  336. {
  337.     Index            index;
  338.     Time            *timeArray;
  339.     
  340.     /* ----------------
  341.      *    sanity check
  342.      * ----------------
  343.      */
  344.     if (tblock == NULL)
  345.     return InvalidTime;
  346.     
  347.     /* ----------------
  348.      *    calculate the index into the transaction data where
  349.      *  our transaction commit time is located
  350.      *
  351.      *  XXX this will be replaced soon when we move to the
  352.      *      new transaction id scheme -cim 3/23/90
  353.      *
  354.      *  The new scheme is here. -mer 5/24/92
  355.      * ----------------
  356.      */
  357.     index = transactionId % TP_NumTimePerBlock;
  358.     
  359.     /* ----------------
  360.      *    return the commit time to the caller
  361.      * ----------------
  362.      */
  363.     timeArray =  (Time *) tblock;
  364.     return (Time)
  365.     timeArray[ index ];
  366. }
  367.  
  368. /* --------------------------------
  369.  *    TransBlockSetCommitTime
  370.  *
  371.  *    This sets the commit time of the specified transaction
  372.  * --------------------------------
  373.  */
  374.  
  375. void
  376. TransBlockSetCommitTime(tblock, transactionId, commitTime)
  377.     Pointer        tblock;
  378.     TransactionId    transactionId;
  379.     Time         commitTime;
  380. {
  381.     Index            index;
  382.     Time            *timeArray;
  383.     
  384.     /* ----------------
  385.      *    sanity check
  386.      * ----------------
  387.      */
  388.     if (tblock == NULL)
  389.     return;
  390.  
  391.     
  392.     /* ----------------
  393.      *    calculate the index into the transaction data where
  394.      *  we sould store our transaction status.  
  395.      *
  396.      *  XXX this will be replaced soon when we move to the
  397.      *      new transaction id scheme -cim 3/23/90
  398.      *
  399.      *  The new scheme is here.  -mer 5/24/92
  400.      * ----------------
  401.      */
  402.     index = transactionId % TP_NumTimePerBlock;
  403.  
  404.     /* ----------------
  405.      *    store the transaction commit time at the specified index
  406.      * ----------------
  407.      */
  408.     timeArray =  (Time *) tblock;
  409.     timeArray[ index ] = commitTime;
  410. }
  411.  
  412. /* ----------------------------------------------------------------
  413.  *               transam i/o support routines
  414.  * ----------------------------------------------------------------
  415.  */
  416.  
  417. /* --------------------------------
  418.  *    TransBlockNumberGetXidStatus
  419.  * --------------------------------
  420.  */
  421. XidStatus
  422. TransBlockNumberGetXidStatus(relation, blockNumber, xid, failP)
  423.     Relation        relation;
  424.     BlockNumber           blockNumber;
  425.     TransactionId    xid;
  426.     bool        *failP;
  427. {
  428.     Buffer           buffer;        /* buffer associated with block */
  429.     Block        block;        /* block containing xstatus */
  430.     XidStatus        xstatus;    /* recorded status of xid */
  431.     bool        localfail;      /* bool used if failP = NULL */
  432.  
  433.     /* ----------------
  434.      *    SOMEDAY place a read lock on the log relation
  435.      *  That someday is today 5 Aug 1991 -mer
  436.      * ----------------
  437.      */
  438.     RelationSetLockForRead(relation);
  439.  
  440.     /* ----------------
  441.      *    get the page containing the transaction information
  442.      * ----------------
  443.      */
  444.     buffer =        ReadBuffer(relation, blockNumber);
  445.     block =          BufferGetBlock(buffer);
  446.  
  447.     /* ----------------
  448.      *    get the status from the block.  note, for now we always
  449.      *  return false in failP.
  450.      * ----------------
  451.      */
  452.     if (failP == NULL)
  453.     failP = &localfail;
  454.     (*failP) = false;
  455.  
  456.     xstatus = TransBlockGetXidStatus(block, xid);
  457.  
  458.     /* ----------------
  459.      *    release the buffer and return the status
  460.      * ----------------
  461.      */
  462.     ReleaseBuffer(buffer);
  463.  
  464.     /* ----------------
  465.      *    SOMEDAY release our lock on the log relation
  466.      * ----------------
  467.      */
  468.     RelationUnsetLockForRead(relation);
  469.  
  470.     return
  471.     xstatus;
  472. }
  473.  
  474. /* --------------------------------
  475.  *    TransBlockNumberSetXidStatus
  476.  * --------------------------------
  477.  */
  478. void
  479. TransBlockNumberSetXidStatus(relation, blockNumber, xid, xstatus, failP)
  480.     Relation        relation;
  481.     BlockNumber          blockNumber;
  482.     TransactionId    xid;
  483.     XidStatus        xstatus;
  484.     bool        *failP;
  485. {
  486.     Buffer           buffer;        /* buffer associated with block */
  487.     Block        block;        /* block containing xstatus */
  488.     bool        localfail;      /* bool used if failP = NULL */
  489.     
  490.     /* ----------------
  491.      *    SOMEDAY gain exclusive access to the log relation
  492.      *
  493.      *  That someday is today 5 Aug 1991 -mer
  494.      * ----------------
  495.      */
  496.     RelationSetLockForWrite(relation);
  497.  
  498.     /* ----------------
  499.      *    get the block containing the transaction status
  500.      * ----------------
  501.      */
  502.     buffer =     ReadBuffer(relation, blockNumber);
  503.     block =       BufferGetBlock(buffer);
  504.     
  505.     /* ----------------
  506.      *    attempt to update the status of the transaction on the block.
  507.      *  if we are successful, write the block. otherwise release the buffer.
  508.      *  note, for now we always return false in failP.
  509.      * ----------------
  510.      */
  511.     if (failP == NULL)
  512.     failP = &localfail;
  513.     (*failP) = false;
  514.     
  515.     TransBlockSetXidStatus(block, xid, xstatus);
  516.  
  517.     if ((*failP) == false)
  518.     WriteBuffer(buffer);
  519.     else
  520.     ReleaseBuffer(buffer);
  521.  
  522.     /* ----------------
  523.      *    SOMEDAY release our lock on the log relation
  524.      * ----------------
  525.      */    
  526.     RelationUnsetLockForWrite(relation);
  527. }
  528.  
  529. /* --------------------------------
  530.  *    TransBlockNumberGetCommitTime
  531.  * --------------------------------
  532.  */
  533. Time
  534. TransBlockNumberGetCommitTime(relation, blockNumber, xid, failP)
  535.     Relation        relation;
  536.     BlockNumber           blockNumber;
  537.     TransactionId    xid;
  538.     bool        *failP;
  539. {
  540.     Buffer           buffer;        /* buffer associated with block */
  541.     Block        block;        /* block containing commit time */
  542.     bool        localfail;      /* bool used if failP = NULL */
  543.     Time        xtime;        /* commit time */
  544.     
  545.     /* ----------------
  546.      *    SOMEDAY place a read lock on the time relation
  547.      *
  548.      *  That someday is today 5 Aug. 1991 -mer
  549.      * ----------------
  550.      */
  551.     RelationSetLockForRead(relation);
  552.     
  553.     /* ----------------
  554.      *    get the block containing the transaction information
  555.      * ----------------
  556.      */
  557.     buffer =         ReadBuffer(relation, blockNumber);
  558.     block =           BufferGetBlock(buffer);
  559.  
  560.     /* ----------------
  561.      *    get the commit time from the block
  562.      *  note, for now we always return false in failP.
  563.      * ----------------
  564.      */
  565.     if (failP == NULL)
  566.     failP = &localfail;
  567.     (*failP) == false;
  568.     
  569.     xtime = TransBlockGetCommitTime(block, xid);
  570.  
  571.     /* ----------------
  572.      *    release the buffer and return the commit time
  573.      * ----------------
  574.      */
  575.     ReleaseBuffer(buffer);
  576.     
  577.     /* ----------------
  578.      *    SOMEDAY release our lock on the time relation
  579.      * ----------------
  580.      */
  581.     RelationUnsetLockForRead(relation);
  582.  
  583.     if ((*failP) == false)
  584.     return xtime;
  585.     else
  586.     return InvalidTime;
  587.  
  588. }
  589.  
  590. /* --------------------------------
  591.  *    TransBlockNumberSetCommitTime
  592.  * --------------------------------
  593.  */
  594. void
  595. TransBlockNumberSetCommitTime(relation, blockNumber, xid, xtime, failP)
  596.     Relation        relation;
  597.     BlockNumber          blockNumber;
  598.     TransactionId    xid;
  599.     Time        xtime;
  600.     bool        *failP;
  601. {
  602.     Buffer           buffer;        /* buffer associated with block */
  603.     Block        block;        /* block containing commit time */
  604.     bool        localfail;      /* bool used if failP = NULL */
  605.  
  606.     /* ----------------
  607.      *    SOMEDAY gain exclusive access to the time relation
  608.      *
  609.      *  That someday is today 5 Aug. 1991 -mer
  610.      * ----------------
  611.      */
  612.     RelationSetLockForWrite(relation);
  613.     
  614.     /* ----------------
  615.      *    get the block containing our commit time
  616.      * ----------------
  617.      */
  618.     buffer =        ReadBuffer(relation, blockNumber);
  619.     block =          BufferGetBlock(buffer);
  620.  
  621.     /* ----------------
  622.      *    attempt to update the commit time of the transaction on the block.
  623.      *  if we are successful, write the block. otherwise release the buffer.
  624.      *  note, for now we always return false in failP.
  625.      * ----------------
  626.      */
  627.     if (failP == NULL)
  628.     failP = &localfail;
  629.     (*failP) = false;
  630.     
  631.     TransBlockSetCommitTime(block, xid, xtime);
  632.  
  633.     if ((*failP) == false)
  634.     WriteBuffer(buffer);
  635.     else
  636.     ReleaseBuffer(buffer);
  637.     
  638.     /* ----------------
  639.      *    SOMEDAY release our lock on the time relation
  640.      * ----------------
  641.      */
  642.     RelationUnsetLockForWrite(relation);
  643.  
  644. }
  645.  
  646. /* --------------------------------
  647.  *    TransGetLastRecordedTransaction
  648.  * --------------------------------
  649.  */
  650. void
  651. TransGetLastRecordedTransaction(relation, xid, failP)
  652.     Relation        relation;
  653.     TransactionId    xid;        /* return: transaction id */
  654.     bool        *failP;
  655. {
  656.     BlockNumber          blockNumber;    /* block number */
  657.     Buffer           buffer;        /* buffer associated with block */
  658.     Block        block;        /* block containing xid status */
  659.     BlockNumber        n;        /* number of blocks in the relation */
  660.     TransactionId    baseXid;
  661.     
  662.     (*failP) = false;
  663.  
  664.     /* ----------------
  665.      *    SOMEDAY gain exclusive access to the log relation
  666.      *
  667.      *  That someday is today 5 Aug. 1991 -mer
  668.      *  It looks to me like we only need to set a read lock here, despite
  669.      *  the above comment about exclusive access.  The block is never 
  670.      *  actually written into, we only check status bits.
  671.      * ----------------
  672.      */
  673.     RelationSetLockForRead(relation);
  674.     
  675.     /* ----------------
  676.      *    we assume the last block of the log contains the last
  677.      *  recorded transaction.  If the relation is empty we return
  678.      *  failure to the user.
  679.      * ----------------
  680.      */
  681.     n = RelationGetNumberOfBlocks(relation);
  682.     if (n == 0) {
  683.     (*failP) = true;
  684.     return;
  685.     }
  686.  
  687.     /* ----------------
  688.      *    get the block containing the transaction information
  689.      * ----------------
  690.      */
  691.     blockNumber =  n-1;
  692.     buffer =     ReadBuffer(relation, blockNumber);
  693.     block =       BufferGetBlock(buffer);
  694.  
  695.     /* ----------------
  696.      *    get the last xid on the block
  697.      * ----------------
  698.      */
  699.     baseXid = blockNumber * TP_NumXidStatusPerBlock;
  700.     
  701.     (void) TransBlockGetLastTransactionIdStatus(block, baseXid, &xid);
  702.     
  703.     ReleaseBuffer(buffer);
  704.  
  705.     /* ----------------
  706.      *    SOMEDAY release our lock on the log relation
  707.      * ----------------
  708.      */
  709.     RelationUnsetLockForRead(relation);
  710. }
  711.